//命名空间
var NMSTopo = {};

NMSTopo.STATE_IMAGE_LOAD = 10;//正在加载图片
NMSTopo.STATE_INIT_LOAD = 20;//正在初始化
NMSTopo.STATE_INIT_OVER = 30;//初始化完成
//布局方式常量
NMSTopo.LAYOUT_FORCE_DIRECT = "forceDirect";
NMSTopo.LAYOUT_NONE = "none";

//构造函数  TOPO对象
NMSTopo.Topo = function (opt){
	// 配置对象
	var option = {
		canvasId : "canvas",//使用画布的ID  默认ID为canvas
      	backGround : "",//背景图路径
      	topoWidth : 0,//拓扑的宽
      	topoHeight : 0,//拓扑的高
      	//是否需要动画
      	animateFlag : true,
      	//动画帧数
      	animateFrames : 30 ,
      	//布局参数
      	layout:{
      		name: NMSTopo.LAYOUT_NONE ,//使用布局方式   [forceDirect / none] 力导向或者不使用布局 
      		param:{
        	  isScale : false, //说明: 默认第一次应用布局,是否自适应屏幕宽高,等比例缩放,默认false
	          isRandom : false,//说明: 默认初始位置是随机Random还是定位location,默认false
	          initAreaW : 100, //说明: 初始分布是的初始宽,默认100px
	          initAreaH : 56,  //说明: 初始分布是的初始高,默认56px
	          energy:0.5,          //说明: 能量值范围0.3-1,  默认0.5
	          iterations :150,     //说明: 力导向的迭代次数,默认150
	          ejectFactor : 2,     //说明: 默认斥力常量,默认2
	          ejectRange : 250,    //说明: 最大斥力范围,超过的不计算节点间斥力,默认2
	          ejectFadeRange : 30, //说明: 节点簇的减弱范围,此范围内ejectFactor-1,默认30
	          condenseFactor : 1,  //说明: 默认引力常量,默认1
	          maxtx : 3,           //说明: 每次迭代的x方向最大移动距离,默认3
	          maxty : 1.68         //说明: 每次迭代的y方向最大移动距离,默认1.68
	        }
      	},
      	nodes:[],// 节点数组
      	edges:[]// 连线数组
	};

	//状态机
	var appState = 0;
	//画笔对象
	var _g2d;
	//画布对象
	var _canvas;
	//动画对象
	var _animate;
	//画布宽高
	var	_canvasWidth;
    var _canvasHeight;

    var _thisTopo = this;
    
	var nodeObjs = new Array();
	var edgeObjs = new Array();

	//当前被选中的连线与坐标
	this.currentNode ;
	this.currentEdge ;
	//是否启了用动画
	this.animateFlag ;

    //将外部传入的 topo 图参数赋值
    function _initOption (opt){
		option.canvasId = opt.canvasId ? opt.canvasId : "canvasId";
		option.backGround = opt.backGround ? opt.backGround : "";
		option.nodes = opt.nodes ? opt.nodes : [];
		option.edges = opt.edges ? opt.edges : [];
		
		option.animateFlag = opt.hasOwnProperty("animateFlag") ? opt.animateFlag : true;

		option.animateFrames = opt.animateFrames ? opt.animateFrames : 30;

		option.topoWidth = opt.topoWidth ? opt.topoWidth : 100;
		option.topoHeight = opt.topoHeight ? opt.topoHeight : 100;
		//如果传入有layout 则进行赋值
		if(opt.layout){
			option.layout.name = opt.layout.name;
			//如果是 力导向布局 则进一步设置参数
			if(option.layout.name==NMSTopo.LAYOUT_FORCE_DIRECT){
				//将用户设置的 参数替换默认值
				for(var paramName in opt.layout.param){
					option.layout.param[paramName] 
						= opt.layout.param[paramName];
				}
			}
		}

		//创建节点
		for(var nodeIndex in option.nodes){
			var nodeOpt = option.nodes[nodeIndex];
			var tmpNode = new NMSTopo.NMSNode(nodeOpt , _thisTopo);
			nodeObjs.push(tmpNode);
		}
		//创建连线
		for(var edgeIndex in option.edges){
			var edgeOpt = option.edges[edgeIndex];
			var tmpEdge = new NMSTopo.NMSEdge(edgeOpt , _thisTopo);
			edgeObjs.push(tmpEdge);
		}
	}

	//初始化 画布 等一些列参数
	function _initCanvas (){
		var id = option.canvasId;
		_canvas = document.getElementById(id[0]=="#"?id.slice(1,id.length):id); //兼容#
		_g2d = _canvas.getContext("2d");

		_canvasWidth = _canvas.width;
		_canvasHeight = _canvas.height;

		if(option.topoWidth <= _canvasWidth){
			option.topoWidth = _canvasWidth;
		}

		if(option.topoHeight <= _canvasHeight){
			option.topoHeight = _canvasHeight;
		}
	}

	//加载图片
	function _loadImg (){
		// 需要加载的图片数量
		var numImages = 0;
		//已经加载的图片
		var loadedImages = 0;
		//记录需要加载的路径
		var imgPaths = [];

		//找到需要加载的图片
		if(option.backGround){
			imgPaths[numImages] = option.backGround;
			numImages++;
		}
		//找到需要加载的图片
		for(var tmpNodeIndex in option.nodes){
			var tmpNode = option.nodes[tmpNodeIndex];
			if(tmpNode.type == "img"){
				imgPaths[numImages] = tmpNode.imgName;
				numImages++;
			}	
		}
		// 开始加载
		for(var i=0; i<numImages ;i++){
			var tmpImg = new Image();
			tmpImg.src = imgPaths[i];
			tmpImg.onload = function(){
				//进度显示
				++loadedImages;
				
				//若加载完成 开始执行回调
				if(loadedImages>=numImages){
					_layoutTopo();
					_renderTopo();
					_startAnimate();
					_addMouseListener();
					_addKeyListener();
				}
			}
		}
	}

	//布局
	function _layoutTopo(){

	}

	//渲染画图
	function _renderTopo(){
		appState = NMSTopo.STATE_INIT_LOAD;
		//画背景
		if( option.backGround.length > 0){
			var tmpImg = new Image();
			tmpImg.src = option.backGround;

			_g2d.save();
			
			var bgPattern = _g2d.createPattern(tmpImg,'repeat');
			_g2d.fillStyle = bgPattern;
			_g2d.globalAlpha = 0.5;
			_g2d.fillRect(0,0,_canvasWidth,_canvasHeight);

			_g2d.restore();
		}

		//画节点
		for(var nodeIndex in nodeObjs){
			var tmpNode = nodeObjs[nodeIndex];
			tmpNode.renderNode(_g2d);
		}
		//画线
		for(var edgeIndex in edgeObjs){
			var tmpEdge = edgeObjs[edgeIndex];
			tmpEdge.renderEdge(_g2d);
		}
	}


	//开启动画 即每S刷新重绘拓扑固定次数
	function _startAnimate(){
		if(option.animateFlag){
			_thisTopo.animateFlag = true;
			_animate = setInterval(
				function(){
					_thisTopo.repaintTopo();
					 console.log("Animate repaint()...");
				} , (1000/option.animateFrames) );
		}else{
			_thisTopo.animateFlag = false;
		}
	}


	this._mouseEvent ;
	//添加鼠标监听
	function _addMouseListener(){
		_mouseEvent = new NMSTopo.MEvent(_canvas, nodeObjs , edgeObjs ,_thisTopo);
	}

	//添加键盘监听
	function _addKeyListener(){
		window.addEventListener('keydown', doKeyDown,true);

		function doKeyDown(e){

		}
	}

	//添加一个节点
	this.addNode = function ( nodeOpt , parentTopo){
		var tmpNode = new NMSTopo.NMSNode(nodeOpt , parentTopo);
		nodeObjs.push(tmpNode); 
	}

	//添加一个连线
	this.addEdge = function ( edgeOpt ,parentTopo ){
		var tmpEdge = new NMSTopo.NMSEdge(edgeOpt , parentTopo);
		edgeObjs.push(tmpEdge);
	}
	//重绘topo
	this.repaintTopo = function (){
		_g2d.clearRect(0, 0, _canvasWidth, _canvasHeight);
		_renderTopo();
	}

	//根据事件重绘
	this._repaintTopoWithEvent = function (e){
		if(this.currentNode){

		}

		_g2d.clearRect(0, 0, _canvasWidth, _canvasHeight);
				//画背景
		if( option.backGround.length > 0){
			var tmpImg = new Image();
			tmpImg.src = option.backGround;

			_g2d.save();
			
			var bgPattern = _g2d.createPattern(tmpImg,'repeat');
			_g2d.fillStyle = bgPattern;
			_g2d.globalAlpha = 0.5;
			_g2d.fillRect(0,0,_canvasWidth,_canvasHeight);

			_g2d.restore();
		}

		var x = e.clientX - _canvas.offsetLeft;
		var y = e.clientY - _canvas.offsetTop;
		//画节点
		for(var nodeIndex in nodeObjs){
			var tmpNode = nodeObjs[nodeIndex];
			tmpNode.renderNode(_g2d , x , y);
		}
		//画线
		for(var edgeIndex in edgeObjs){
			var tmpEdge = edgeObjs[edgeIndex];
			tmpEdge.renderEdge(_g2d , x , y);
		}
	}
	
	//加载布局显示topo 供外部调用
	this.initAndShowTopo = function(){
		appState = NMSTopo.STATE_IMAGE_LOAD;
		_loadImg();
		appState = NMSTopo.STATE_INIT_OVER;
	}

	//判断浏览器是否支持canvas
	if( !NMSTopo._canvasSupport() ){
		throw new Error("Your browser does not support canvas");
	}
    //加载参数
    _initOption(opt);
	//加载画布
    _initCanvas(opt);


	return this;
};

NMSTopo.Topo.prototype = {

}


NMSTopo.MEvent = function ( canvas  , nodes , edges ,topo){

	canvas.addEventListener("mousedown", doMouseDown,false); 	//摁下
	canvas.addEventListener("mousemove", doMouseMove,false); 	//移动
	canvas.addEventListener("mouseup", doMouseUp,false);   		//抬起
	canvas.addEventListener("click", doMouseClick,false);   	//点击 mouseup之后触发

	//记录上一次鼠标的事件
	var _e={};	

	var showTimer ;

	function doMouseDown (e) {
		e=e||event;
		var x = e.clientX - canvas.offsetLeft;
		var y = e.clientY - canvas.offsetTop;

		_e = e;
		//启动 定时器，以平均每秒60fps(1000/16)的帧率刷新拓扑图
		//若topo 启用了动画 则不需要执行 此方法，动画会每秒按一定次数刷新topo
		if(!topo.animateFlag){

			showTimer = setInterval(function(e){
				topo._repaintTopoWithEvent(e);
				console.log("_repaintTopoWithEvent(e)...");
			},16,_e);

		}else{
			topo._repaintTopoWithEvent(_e);
		}
	}


	function doMouseMove (e) {
		var x = e.clientX - canvas.offsetLeft;
		var y = e.clientY - canvas.offsetTop;

		var _x = _e.clientX - canvas.offsetLeft;
		var _y = _e.clientY - canvas.offsetTop;

		//此方法 仅当 topo 中选中节点存在时候 才会触发
		if(topo.currentNode && topo.currentNode.canMove){
			topo.currentNode.x = topo.currentNode.x + (x-_x);
			topo.currentNode.y = topo.currentNode.y + (y-_y);
		}
		_e=e;
	}	

	function doMouseUp(e) {


		if(topo.currentNode){

			topo.currentNode.canMove = false;

			if(topo.currentNode.isFocus){
				//测试点击
				console.log("点击了Node :" + topo.currentNode.labelText);
			}
		}

		canvas.onmousemove=null;
		if(showTimer){
			clearInterval(showTimer);
		}

	}

	function doMouseClick (e) {

		var clickCount = e.detail;


		if( clickCount == 1 ) {


			setCurrentTopoNull();
		} else if(clickCount == 2){

			if(topo.currentNode && topo.currentNode.isFocus){
				console.log("ClickCount=2 显示"+topo.currentNode.labelText+"菜单...");
			}else{
				setCurrentTopoNull();
			}
		}

	}

	//将 当前topo中选中节点置为null
	function setCurrentTopoNull(){
		if(topo.currentNode && !topo.currentNode.isFocus){
			topo.currentNode = null;
			if(!topo.animateFlag){
				topo.repaintTopo();
			}
		}
	}

	//查看鼠标点击是否在连线
	function collideCheckEdge(){

	}

}


//节点对象	构造函数 	
//nodeOpt 节点参数
//renderMethod(g2d , nodeObj)可以手工指定其渲染方式
NMSTopo.NMSNode = function (nodeOpt , topo){ 
	//说明: 节点Label颜色, 优先级低于节点自带属性, 默认#878787
	this.textColor = nodeOpt.textColor ? nodeOpt.textColor :"#878787";
	//说明: 节点Label字体大小, 优先级低于节点自带属性, 默认10px
	this.textSize = nodeOpt.textSize ? nodeOpt.textSize : 10;
	//是否显示标签  默认显示
	this.showLabel = nodeOpt.hasOwnProperty("showLabel") ? nodeOpt.showLabel : true;

	this.labelText = nodeOpt.labelText ? nodeOpt.labelText : "";

	//填充颜色
	this.fillColor = nodeOpt.fillColor ? nodeOpt.fillColor : "rgba(120,120,120,0.7)";
	//获取焦点的时候填充的颜色
	this.focusColor = nodeOpt.focusColor ? nodeOpt.focusColor : "rgba(40,40,40,0.7)";
	//边框颜色
	this.borderColor = nodeOpt.borderColor ? nodeOpt.borderColor : "rgba(50,150,250,1)";
	//边框宽度 默认1px
	this.borderWidth = nodeOpt.borderWidth ? nodeOpt.borderWidth : 1;

	//节点的初始坐标  统一定为左上角坐标
	this.x = nodeOpt.x ? nodeOpt.x : 10 ;
	this.y = nodeOpt.y ? nodeOpt.y : 10 ;
	//type 类型有  img、circle、rect、udRender 分别表示图片、圆形、矩形、自定义
	//自定义的时候 需要传入 renderMethod 这个参数
	this.type = nodeOpt.type ? nodeOpt.type : "circle";

	//默认半径type为circle时生效  默认12像素
	this.radius = nodeOpt.radius ? nodeOpt.radius : 12 ;
	//长宽 node占据形状的最小矩形 renderNode使用此来确定 node 的填充大小
	this.width = nodeOpt.width ? nodeOpt.width : 24 ;
	this.height = nodeOpt.height ? nodeOpt.height : 24 ;
	//若type类型为img时需传入图片路径  
	this.imgName = nodeOpt.imgName ? nodeOpt.imgName : "";
	//渲染方法当type为 udRender时候 从外部传入
	this.renderMethod = nodeOpt.renderMethod ? nodeOpt.renderMethod : "null";
	//所属拓扑图
	this.parentTopo = topo;
	// 是否允许拖拽  当鼠标按下时第一次计算若点在node 范围内 则将此标志置为true
	//鼠标松开之前都无需重新计算 提高效率
	this.canMove = false;
	//是否有焦点可以相应鼠标事件 目前决定是否可以响应鼠标单双击事件
	this.isFocus = false;

	//力导向布局时使用到
	this.force_x = 0;
	this.force_y = 0;

	return this;
}

NMSTopo.NMSNode.prototype.needDrawSelected = function (){
	if(this.parentTopo.currentNode==this){
		return true;
	}else {
		return false;
	}
}

//为原型添加方法  渲染节点
NMSTopo.NMSNode.prototype.renderNode = function ( g2d , x , y ){

	g2d.lineWidth = this.borderWidth;
	//画图片节点
	// if("img"== this.type){
	// 	g2d.beginPath();
	// 	g2d.moveTo( this.x , this.y );
	// 	g2d.lineTo( this.x+this.width , this.y );
	// 	g2d.lineTo( this.x+this.width , this.y+this.height );
	// 	g2d.lineTo( this.x , this.y+this.width );
	// 	g2d.lineTo( this.x , this.y );
	// }else 
	//画矩形节点
	if("rect"== this.type || "img"== this.type){
		g2d.fillStyle = this.fillColor;
		g2d.beginPath();
		g2d.moveTo( this.x , this.y );
		g2d.lineTo( this.x+this.width , this.y );
		g2d.lineTo( this.x+this.width , this.y+this.height );
		g2d.lineTo( this.x , this.y+this.width );
		g2d.lineTo( this.x , this.y );
	}
	//画自定义节点
	else if("udRender"== this.type && "null"!=this.renderMethod){
		this.renderMethod(g2d,this);
	}
	//默认为圆形节点
	else{
		g2d.fillStyle = this.fillColor;
		g2d.beginPath();
		// context.arc(x,y,r,sAngle,eAngle,counterclockwise);
		//x	圆的中心的 x 坐标。
		// y	圆的中心的 y 坐标。
		// r	圆的半径。
		// sAngle	起始角，以弧度计。（弧的圆形的三点钟位置是 0 度）。
		// eAngle	结束角，以弧度计。
		// counterclockwise	可选。规定应该逆时针还是顺时针绘图。False = 顺时针，true = 逆时针。
		g2d.arc(this.x+this.radius , this.y+this.radius ,this.radius , 0 ,2*Math.PI, true);
		
	}

	if( this.canMove || (x && y && g2d.isPointInPath(x, y)&& !this.canMove) ){
		g2d.fillStyle = this.focusColor;
		this.canMove = true;
		this.isFocus = true;
		this.parentTopo.currentNode = this; 
	}else{
		this.canMove = false;
		this.isFocus = false;
	}

	if(this.type == "circle" || this.type == "rect"){
		if(this.needDrawSelected()){
			g2d.fillStyle = this.focusColor;
		}
		g2d.fill();
		g2d.closePath();
	} else if(this.type == "img"){
		if(this.needDrawSelected()){
			g2d.strokeStyle = this.borderColor;	
			g2d.strokeRect(this.x, this.y, this.width, this.height);
		}
		var tmpImg = new Image();
		tmpImg.src = this.imgName;
		g2d.drawImage(tmpImg, this.x+1, this.y+1, this.width-1, this.height-1);
	}

	//drawLabel
	// if(this.showLabel){
	// 	console.log("label is : " + this.labelText);
	// }
}



//连线对象  构造函数
//edgeOpt 连线参数
NMSTopo.NMSEdge = function ( edgeOpt , topo){



	return this;
}

NMSTopo.NMSEdge.prototype.renderEdge = function( g2d , x , y){



}

/**
 * 判断浏览器是否支持canvas(私有方法)
 */
NMSTopo._canvasSupport = function (){
	return !!document.createElement("canvas").getContext;
}